##################################################################
# File : /lua/ui/dialogs/window.lua
# Description :Generic resizable window
# Author : GPG / Neruz
##################################################################

local Group = import('/lua/maui/group.lua').Group
local Bitmap = import('/lua/maui/bitmap.lua').Bitmap
local Button = import('/lua/maui/button.lua').Button
local Dragger = import('/lua/maui/dragger.lua').Dragger
local Checkbox = import('/lua/maui/checkbox.lua').Checkbox
local LayoutHelpers = import('/lua/maui/layouthelpers.lua')
local Prefs = import('/lua/user/prefs.lua')
local Border = import('/lua/maui/border.lua').Border
local UIUtil = import('/lua/ui/uiutil.lua')

Window = Class(Group) {
    __init = function(self, parent, title, icon, minimize, close, config, lockSize, lockPosition, prefID)
        Group.__init(self, parent)
        
        self._resizeGroup = Group(self)
        LayoutHelpers.FillParent(self._resizeGroup, self)
        self._resizeGroup.Depth:Set(function() return self.Depth() + 100 end)
        self._resizeGroup:DisableHitTest()
             
        self._windowGroup = Group(self)
        LayoutHelpers.FillParent(self._windowGroup, self)
        self._windowGroup:DisableHitTest()
        
    	self._border = Border(self._windowGroup)
    	self._border:DisableHitTest()
    	self._border:SetSolidColor('Gray')
    	self._border:SetAlpha(0.5)
#     	self._border:SetTextures(
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_vert_l.dds'),
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_horz_um.dds'),
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_ul.dds'),
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_ur.dds'),
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_ll.dds'),
#         	UIUtil.SkinnableFile('/game/generic_brd/generic_brd_lr.dds'))
        self._border:LayoutAroundControl(self._windowGroup)
        self._border.Depth:Set(self.Depth() + 1)
	    self._bg = Bitmap(self._windowGroup, UIUtil.SkinnableFile('/game/generic_brd/generic_brd_m.dds'))
	    self._border:LayoutControlInside(self._bg)
	    self._bg.Width:Set(function() return self._bg.Right() - self._bg.Left() end)
	    self._bg.Height:Set(function() return self._bg.Bottom() - self._bg.Top() end)
        
        self.tl = Bitmap(self._resizeGroup)
        self.tr = Bitmap(self._resizeGroup)
        self.bl = Bitmap(self._resizeGroup)
        self.br = Bitmap(self._resizeGroup)
        self.tm = Bitmap(self._resizeGroup)
        self.bm = Bitmap(self._resizeGroup)
        self.ml = Bitmap(self._resizeGroup)
        self.mr = Bitmap(self._resizeGroup)
         
		self._borderSize = 5
        self._sizeLock = false
        self._lockPosition = lockPosition or {false, false}
        self._lockSize = lockSize or {false, false}
        self._xMin = 0
        self._yMin = 0
         
        self.tl:SetSolidColor('Blue')
        self.tr:SetSolidColor('Blue')
        self.bl:SetSolidColor('Blue')
        self.br:SetSolidColor('Blue')
        self.tm:SetSolidColor('Blue')
        self.bm:SetSolidColor('Blue')
        self.ml:SetSolidColor('Blue')
        self.mr:SetSolidColor('Blue')
        
        # Set alpha of resize controls to 0 so that they still get resize events, but are not seen
        
        self.tl:SetAlpha(0)
        self.tr:SetAlpha(0)
        self.bl:SetAlpha(0)
        self.br:SetAlpha(0)
        self.tm:SetAlpha(0)
        self.bm:SetAlpha(0)
        self.ml:SetAlpha(0)
        self.mr:SetAlpha(0)
        
        self.tl.Height:Set(self._borderSize)
        self.tl.Width:Set(self._borderSize)
        self.tl.Top:Set(self.Top)
        self.tl.Left:Set(self.Left)
        
        self.tr.Height:Set(self._borderSize)
        self.tr.Width:Set(self._borderSize)
        self.tr.Top:Set(self.Top)
        self.tr.Right:Set(self.Right)
        
        self.bl.Height:Set(self._borderSize)
        self.bl.Width:Set(self._borderSize)
        self.bl.Bottom:Set(self.Bottom)
        self.bl.Left:Set(self.Left)
        
        self.br.Height:Set(self._borderSize)
        self.br.Width:Set(self._borderSize)
        self.br.Bottom:Set(self.Bottom)
        self.br.Right:Set(self.Right)
        
        self.tm.Height:Set(self._borderSize)
        self.tm.Left:Set(self.tl.Right)
        self.tm.Right:Set(self.tr.Left)
        self.tm.Top:Set(self.tl.Top)
        
        self.bm.Height:Set(self._borderSize)
        self.bm.Left:Set(self.bl.Right)
        self.bm.Right:Set(self.br.Left)
        self.bm.Top:Set(self.bl.Top)
        
        self.ml.Width:Set(self._borderSize)
        self.ml.Left:Set(self.tl.Left)
        self.ml.Top:Set(self.tl.Bottom)
        self.ml.Bottom:Set(self.bl.Top)
        
        self.mr.Width:Set(self._borderSize)
        self.mr.Right:Set(self.tr.Right)
        self.mr.Top:Set(self.tr.Bottom)
        self.mr.Bottom:Set(self.br.Top)
    
        self.TitleGroup = Group(self)
        self.TitleGroup.Top:Set(self.tm.Top)
        self.TitleGroup.Left:Set(self.tl.Left)
        self.TitleGroup.Right:Set(self.tr.Right)
        self.TitleGroup.Height:Set(30)
        self.TitleGroup.Depth:Set(function() return self._windowGroup.Depth() + 2 end)
#         
#         if icon then
#             self._titleIcon = Bitmap(self.TitleGroup, icon)
#             LayoutHelpers.AtLeftTopIn(self._titleIcon, self.TitleGroup, 2, 2)
#         end
#         
        if title then
        	self._titleBar = Bitmap(self.TitleGroup)
        	LayoutHelpers.FillParent(self._titleBar, self.TitleGroup)
        	self._titleBar:SetSolidColor('Gray')
        	self._titleBar:SetAlpha(0.2)
            self._title = UIUtil.CreateText(self.TitleGroup, LOC(title), 16)
            if icon then
                self._title.Left:Set(function() return self._titleIcon.Right() + 5 end)
                LayoutHelpers.AtVerticalCenterIn(self._title, self._titleIcon)
            else
                LayoutHelpers.AtLeftTopIn(self._title, self.TitleGroup, 7, 7)
            end
            self._xMin = self._title.Width() + 15
            self._yMin = self._title.Height() + 15
        end
#         
#         self._closeBtn = UIUtil.CreateButtonStd(self.TitleGroup, "/dialogs/close_btn/close")
#         LayoutHelpers.AtRightTopIn(self._closeBtn, self.TitleGroup, 7, 7)
#         self._closeBtn.OnClick = function(control)
#             self:OnClose(control)
#         end
#         
#         if pin then
#             self._pinBtn = Checkbox(self.TitleGroup,
#                 UIUtil.UIFile('/dialogs/pin/pin_up.dds'),
#                 UIUtil.UIFile('/dialogs/pin/pinned_up.dds'),
#                 UIUtil.UIFile('/dialogs/pin/pin_over.dds'),
#                 UIUtil.UIFile('/dialogs/pin/pinned_over.dds'),
#                 UIUtil.UIFile('/dialogs/pin/pin_dis.dds'),
#                 UIUtil.UIFile('/dialogs/pin/pinned_dis.dds'))
#             LayoutHelpers.LeftOf(self._pinBtn, self._closeBtn)
#             self._pinBtn.OnCheck = function(control, checked)
#                 self:OnPinCheck(checked)
#             end
#         end
#         
#         if config then
#             self._configBtn = Button(self.TitleGroup,
#                 UIUtil.UIFile('/dialogs/config_btn/config_btn_up.dds'),
#                 UIUtil.UIFile('/dialogs/config_btn/config_btn_down.dds'),
#                 UIUtil.UIFile('/dialogs/config_btn/config_btn_over.dds'),
#                 UIUtil.UIFile('/dialogs/config_btn/config_btn_dis.dds'))
#             if pin then
#                 LayoutHelpers.LeftOf(self._configBtn, self._pinBtn)
#             else
#                 LayoutHelpers.LeftOf(self._configBtn, self._closeBtn)
#             end
#             self._configBtn.OnClick = function(control)
#                 self:OnConfigClick()
#             end
#         end
#         
        self.ClientGroup = Group(self)
        self.ClientGroup.Top:Set(self.TitleGroup.Bottom)
        self.ClientGroup.Left:Set(self.Left)
        self.ClientGroup.Height:Set(self.Height)
        self.ClientGroup.Width:Set(self.Width)
        self.ClientGroup.Right:Set(self.Right)
        self.ClientGroup.Bottom:Set(self.Bottom)
        self.ClientGroup.Depth:Set(function() return self.Depth() + 1 end)
       
        local function StartSizing(event, xControl, yControl)
        	if xControl and self._lockSize[1] then return
        	elseif yControl and self._lockSize[2] then return end
            local drag = Dragger()
            local x_max = true
            local y_max = true
            if event.MouseX < self.tl.Right() then
                x_max = false
            end
            if event.MouseY < self.tl.Bottom() then
                y_max = false
            end
            drag.OnMove = function(dragself, x, y)
                if xControl then
                    local newX
                    if x_max then
                        tempNewX = math.min(math.max(x, self.Left() + self._xMin), parent.Right())
                        newX = math.max(tempNewX, self.Left() + 2 * ((self.Right() - self.Left()) - self._border.Width()))
                    else
                        newX = math.min(math.max(x, 0), self.Right() - self._xMin)
                    end
                    xControl:Set(newX)
                end
                if yControl then
                    local newY 
                    if y_max then
                        tempNewY = math.min(math.max(y, self.Top() + self._yMin), parent.Bottom())
                        newY = math.max(tempNewY, self.Top() + 2 * ((self.Bottom() - self.Top()) - self._border.Height()))
                    else
                        newY = math.min(math.max(y, 0), self.Bottom() - self._yMin)
                    end
                    LOG(self.Bottom(), yControl())
                    yControl:Set(newY)
                end
                self:OnResize(x, y, not self._sizeLock)
                if not self._sizeLock then
                    self._sizeLock = true
                end
            end
            drag.OnRelease = function(dragself)
                self._sizeLock = false
                self._resizeGroup:SetAlpha(0, true)
                GetCursor():Reset()
                drag:Destroy()
                if prefID then
                    Prefs.SetToCurrentProfile(prefID, {top = self.Top(), left = self.Left(), right = self.Right(), bottom = self.Bottom()})
                end
                self:OnResizeSet()
            end
            drag.OnCancel = function(dragself)
                self._sizeLock = false
                GetCursor():Reset()
                drag:Destroy()
            end
            PostDragger(self:GetRootFrame(), event.KeyCode, drag)
        end
                
        local function RolloverHandler(control, event, xControl, yControl, cursor)
            if self._lockSize[1] and self._lockSize[2] then return end
            if not self._sizeLock then
                if event.Type == 'MouseEnter' then
                    self._resizeGroup:SetAlpha(1, true)
                    GetCursor():SetTexture(UIUtil.GetCursor(cursor))
                elseif event.Type == 'MouseExit' then
                    self._resizeGroup:SetAlpha(0, true)
                    GetCursor():Reset()
                elseif event.Type == 'ButtonPress' then
                    StartSizing(event, xControl, yControl)
                end
            end
        end
        
        self.br.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Right, self.Bottom, 'NW_SE')
        end
        self.bl.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Left, self.Bottom, 'NE_SW')
        end
        self.bm.HandleEvent = function(control, event)
            RolloverHandler(control, event, nil, self.Bottom, 'N_S')
        end
        self.tr.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Right, self.Top, 'NE_SW')
        end
        self.tl.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Left, self.Top, 'NW_SE')
        end
        self.tm.HandleEvent = function(control, event)
            RolloverHandler(control, event, nil, self.Top, 'N_S')
        end
        self.mr.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Right, nil, 'W_E')
        end
        self.ml.HandleEvent = function(control, event)
            RolloverHandler(control, event, self.Left, nil, 'W_E')
        end
        
        self.TitleGroup.HandleEvent = function(control, event)
            if not self._sizeLock then
                if event.Type == 'ButtonPress' then
                    if self._lockPosition[1] and self._lockPosition[2] then return end
                    local drag = Dragger()
                    local offX = event.MouseX - self.Left()
                    local offY = event.MouseY - self.Top()
                    local height = self.Height()
                    local width = self.Width()
                    drag.OnMove = function(dragself, x, y)
                    	if not self._lockPosition[1] then
                       		self.Left:Set(math.min(math.max(x-offX, 0), parent.Right() - self.Width()))
                       	end
                       	if not self._lockPosition[2] then
                        	self.Top:Set(math.min(math.max(y-offY, 0), parent.Bottom() - self.Height()))
                        end
                        local tempRight = self.Left() + width
                        local tempBottom = self.Top() + height
                        self.Right:Set(tempRight)
                        self.Bottom:Set(tempBottom)
                        self:OnMove(x, y, not self._sizeLock)
                        if not self._sizeLock then
                            GetCursor():SetTexture(UIUtil.GetCursor('MOVE_WINDOW'))
                            self._sizeLock = true
                        end
                    end
                    drag.OnRelease = function(dragself)
                        self._sizeLock = false
                        GetCursor():Reset()
                        drag:Destroy()
                        if prefID then
                            Prefs.SetToCurrentProfile(prefID, {top = self.Top(), left = self.Left(), right = self.Right(), bottom = self.Bottom()})
                        end
                        self:OnMoveSet()
                    end
                    drag.OnCancel = function(dragself)
                        self._sizeLock = false
                        GetCursor():Reset()
                        drag:Destroy()
                    end
                    PostDragger(self:GetRootFrame(), event.KeyCode, drag)
                end
            end
        end
        
        self.HandleEvent = function(control, event)
            if event.Type == 'WheelRotation' then
                self:OnMouseWheel(event.WheelRotation)
            end
        end
        self.OnHide = function(control, hidden)
            control._resizeGroup:SetHidden(hidden)
            control:OnHideWindow(control, hidden)
        end
        
        local OldHeightOnDirty = parent.Height.OnDirty
        local OldWidthOnDirty = parent.Width.OnDirty
        parent.Height.OnDirty = function(var)
            if self.Bottom() > parent.Bottom() then
                local Height = math.min(self.Height(), parent.Height())
                self.Bottom:Set(parent.Bottom)
                self.Top:Set(function() return self.Bottom() - Height end)
            end
            if OldHeightOnDirty then
                OldHeightOnDirty(var)
            end
        end
        parent.Width.OnDirty = function(var)
            if self.Right() > parent.Right() then
                local Width = math.min(self.Width(), parent.Width())
                self.Right:Set(parent.Right)
                self.Left:Set(function() return self.Right() - Width end)
            end
            if OldWidthOnDirty then
                OldWidthOnDirty(var)
            end
        end
    end,
    
    GetClientGroup = function(self)
        return self.ClientGroup
    end,
    
    SetSizeLock = function(control, locked)
        self._lockSize(locked)
    end,
    
    SetPositionLock = function(control, locked)
        self._lockPosition(locked)
    end,
    
    SetMinimumResize = function(control, xDimension, yDimension)
        control._xMin = xDimension or 0
        control._yMin = yDimension or 0
    end,
    
    SetWindowAlpha = function(control, alpha)
        control._windowGroup:SetAlpha(alpha, true)
    end,
    
    SetTitle = function(control,text)
        control._title:SetText(LOC(text))
    end,
    
    IsPinned = function(control)
        if control._pinBtn then
            return control._pinBtn:IsChecked()
        else
            return false
        end
    end,
        
    OnDestroy = function(control)
        control._resizeGroup:Destroy()
    end,
    
    #
    # The following are functions that can be overloaded
    #
    OnResize = function(control, x, y, firstFrame) end,
    OnResizeSet = function(control) end,
    
    OnMove = function(control, x, y, firstFrame) end,
    OnMoveSet = function(control) end,
    
    OnPinCheck = function(control, checked) end,
    OnConfigClick = function(control) end,
    
    OnMouseWheel = function(control, rotation) end,
    
    OnClose = function(control) end,
    OnHideWindow = function(control, hidden) end,
}